#!/usr/bin/python3
"""
Inputs for ostree commits

Pull the commits specified by `references` into a newly created
repository. Optionally, if `ref` was specified, create an new
reference for that commit.

The returned data in `refs` is a dictionary where the keys are
commit ids and the values are dictionries. The latter will
contain `ref` it was specified.
"""


import os
import json
import sys
import subprocess

from osbuild import inputs


SCHEMA = """
"additionalProperties": false,
"required": ["type", "origin", "references"],
"properties": {
  "type": {
    "enum": ["org.osbuild.ostree"]
  },
  "origin": {
    "description": "The origin of the input (pipeline or source)",
    "type": "string",
    "enum": ["org.osbuild.source", "org.osbuild.pipeline"]
  },
  "references": {
    "description": "Commit identifier",
    "oneOf": [{
      "type": "array",
      "items": {
        "type": "string"
      }
    }, {
      "type": "object",
      "additionalProperties": false,
      "minProperties": 1,
      "patternProperties": {
        ".*": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "ref": {
                "type": "string",
                "description": "OSTree reference to create for this commit"
            }
          }
        }
      }
    }]
  }
}
"""


def ostree(*args, _input=None, **kwargs):
    args = list(args) + [f'--{k}={v}' for k, v in kwargs.items()]
    print("ostree " + " ".join(args), file=sys.stderr)
    subprocess.run(["ostree"] + args,
                   encoding="utf-8",
                   stdout=sys.stderr,
                   input=_input,
                   check=True)


def export(checksums, cache, output):
    repo_cache = os.path.join(cache, "repo")

    repo_out = os.path.join(output, "repo")
    ostree("init", mode="archive", repo=repo_out)

    refs = {}
    for commit, options in checksums.items():
        # Transfer the commit: remote → cache
        print(f"exporting {commit}", file=sys.stderr)

        ostree("pull-local", repo_cache, commit,
               repo=repo_out)

        ref = options.get("ref")
        if ref:
            ostree("refs", "--create", ref, commit,
                   repo=repo_out)

        refs[commit] = options

    reply = {
        "path": repo_out,
        "data": {
            "refs": refs
        }
    }

    return reply


class OSTreeInput(inputs.InputService):

    def map(self, store, origin, refs, target, _options):

        if origin == "org.osbuild.pipeline":
            for ref, options in refs.items():
                source = store.read_tree(ref)
                with open(os.path.join(source, "compose.json"), "r") as f:
                    compose = json.load(f)
                commit_id = compose["ostree-commit"]
                reply = export({commit_id: options}, source, target)
        else:
            source = store.source("org.osbuild.ostree")
            reply = export(refs, source, target)

        return reply


def main():
    service = OSTreeInput.from_args(sys.argv[1:])
    service.main()


if __name__ == '__main__':
    main()
